#[cfg(test)]
mod self_ref {
    struct SelfRef<'a> {
        value: String,

        // 该引用指向上面的value
        pointer_to_value: &'a str,
    }

    #[test]
    fn sf() {
        let s = "aaa".to_string();
        let v = SelfRef {
            value: s, //试图同时使用值和值的引用，最终所有权转移和借用一起发生了
            // pointer_to_value: &s //err
            pointer_to_value: "asss",
        };
    }

    #[derive(Debug)]
    struct WhatAboutThis<'a> {
        name: String,
        nickname: Option<&'a str>,
    }

    // Option 分两步
    #[test]
    fn wt() {
        let mut tricky = WhatAboutThis {
            name: "Annabelle".to_string(),
            nickname: None,
        };
        tricky.nickname = Some(&tricky.name[..4]);
        println!("{:?}", tricky);
        // Option 这个方法可以工作，但是这个方法的限制较多，例如从一个函数创建并返回它是不可能的
    }
    // fn creator () -> WhatAboutThis {
    //     let mut tricky = WhatAboutThis {
    //         name: "Annabelle".to_string(),
    //         nickname: None,
    //     };
    //     tricky.nickname = Some(&tricky.name[..4]);
    //     tricky
    // }
}

#[cfg(test)]
mod self_ref_unsafe {
    use std::marker::PhantomPinned;
    use std::pin::Pin;
    use std::ptr::NonNull;

    struct SelfRef {
        value: String,
        //pointer_to_value 中直接存储裸指针，而不是 Rust 的引用，因此不再受到 Rust 借用规则和生命周期的限制，
        // 而且实现起来非常清晰、简洁。但是缺点就是，通过指针获取值时需要使用 unsafe 代码。
        pointer_to_value: *const String,
        pointer_to_value_mut: *mut String, //裸指针来修改 String，但是需要将 *const 修改为 *mut
    }

    impl SelfRef {
        fn new(txt: &str) -> Self {
            SelfRef {
                value: String::from(txt),
                pointer_to_value: std::ptr::null(),
                pointer_to_value_mut: std::ptr::null_mut(),
            }
        }

        fn init(&mut self) {
            let self_ref: *const String = &self.value;
            self.pointer_to_value = self_ref;
            let self_ref: *mut String = &mut self.value;
            self.pointer_to_value_mut = self_ref;
        }

        fn value(&self) -> &str {
            &self.value
        }

        fn pointer_to_value(&self) -> &String {
            assert!(
                !self.pointer_to_value.is_null(),
                "Test::b called without Test::init being called first"
            );
            unsafe { &*(self.pointer_to_value) }
        }
        fn pointer_to_value_mut(&self) -> &String {
            assert!(
                !self.pointer_to_value.is_null(),
                "Test::b called without Test::init being called first"
            );
            unsafe { &*(self.pointer_to_value) }
        }
    }

    #[test]
    fn sf() {
        let mut t = SelfRef::new("hello");
        t.init();
        // 打印值和指针地址
        println!("{}, {:p}", t.value(), t.pointer_to_value());

        t.value.push_str(", world");
        unsafe {
            (&mut *t.pointer_to_value_mut).push_str("!");
        }

        println!("{}, {:p}", t.value(), t.pointer_to_value());
    }

    // 无法被移动的 Pin,目前你只需要知道它可以固定住一个值，防止该值在内存中被移动

    // 自引用最麻烦的就是创建引用的同时，值的所有权会被转移，而通过 Pin 就可以很好的防止这一点
    struct Unmovable {
        data: String,
        slice: NonNull<String>,
        _pin: PhantomPinned,
    }

    impl Unmovable {
        // 为了确保函数返回时数据的所有权不会被转移，我们将它放在堆上，唯一的访问方式就是通过指针
        fn new(data: String) -> Pin<Box<Self>> {
            let res = Unmovable {
                data,
                // 只有在数据到位时，才创建指针，否则数据会在开始之前就被转移所有权
                slice: NonNull::dangling(),
                _pin: PhantomPinned,
            };
            let mut boxed = Box::pin(res);

            let slice = NonNull::from(&boxed.data);
            // 这里其实安全的，因为修改一个字段不会转移整个结构体的所有权
            unsafe {
                let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
                Pin::get_unchecked_mut(mut_ref).slice = slice;
            }
            boxed
        }
    }

    #[test]
    fn pin() {
        // Pin 在这里并没有魔法，它也并不是实现自引用类型的主要原因，最关键的还是里面的裸指针的使用，
        // 而 Pin 起到的作用就是确保我们的值不会被移走，否则指针就会指向一个错误的地址！

        let unmoved = Unmovable::new("hello".to_string());
        // 只要结构体没有被转移，那指针就应该指向正确的位置，而且我们可以随意移动指针
        let still_unmoved = unmoved;
        assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));

        // 因为我们的类型没有实现 `Unpin` 特征，下面这段代码将无法编译
        // let mut new_unmoved = Unmovable::new("world".to_string());
        // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
    }
}
